#include <iostream>
#include <string>
#include <cerrno>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include "thread_pool_singal.hpp"
#include "Task.hpp"

using namespace std;

void Usage(string proc)
{
    cout << "Usage \r\t" << proc << " server_port" << endl;
}

// void ServerIO(int new_sock)
// {
//     while (true)
//     {
//         char buffer[1024];
//         memset(buffer, 0, sizeof(buffer));
//         ssize_t s = read(new_sock, buffer, sizeof(buffer));
//         if (s > 0)
//         {
//             buffer[s] = 0;
//             cout << "server # " << buffer;

//             string message = ">>>server<<< ";
//             message += buffer;
//             write(new_sock, message.c_str(), message.size());
//         }
//         else if (s == 0)
//         {
//             cout << "client quit..." << endl;
//             break;
//             ;
//         }
//         else
//         {
//             cerr << "read error" << errno << endl;
//             break;
//         }
//     }
// }

// void *Handler(void *args)
// {
//     pthread_detach(pthread_self());

//     int sock = *(int *)args;
//     // new的对象不用之后需要及时delete
//     delete (int *)args;

//     ServerIO(sock);
//     close(sock);
// }

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        return 1;
    }

    // 1. 创建套接字
    int listen_sock = socket(AF_INET, SOCK_STREAM, 0);
    if (listen_sock < 0)
    {
        cerr << "socket failed " << errno << endl;
        return 2;
    }

    // 2. bind:绑定端口号和IP
    struct sockaddr_in local;
    memset(&local, 0, sizeof(local));
    local.sin_family = AF_INET;
    local.sin_port = htons(atoi(argv[1]));
    local.sin_addr.s_addr = INADDR_ANY;
    if (bind(listen_sock, (struct sockaddr *)&local, sizeof(local)) == -1)
    {
        cerr << "bind failed " << errno << endl;
        return 3;
    }

    // 3. listen:监听客户端的申请
    const int back_log = 5;
    if (listen(listen_sock, back_log) == -1)
    {
        cerr << "listen failed " << errno << endl;
        return 4;
    }

    // 忽略子进程的退出时发送的SIGCHLD信号，子进程自动释放资源
    // signal(SIGCHLD, SIG_IGN);

    // 4. accept:接收客户端的请求
    for (;;)
    {
        struct sockaddr_in client_peer;
        socklen_t len = sizeof(client_peer);
        memset(&client_peer, 0, sizeof(client_peer));
        int new_sock = accept(listen_sock, (struct sockaddr *)&client_peer, &len);
        if (new_sock == -1)
        {
            // 结束本次循环，重新accept新的客户请求，直到成功接收客户请求
            continue;
        }

        uint16_t client_port = ntohs(client_peer.sin_port);
        string client_ip = inet_ntoa(client_peer.sin_addr);
        cout << "A new client link [" << client_ip << ":" << client_port << "] #" << new_sock << endl;

        // 5. 提供服务
        // version one ---只支持一个client链接
        // ServerIO(new_sock);

        // version two ---能支持多个client链接(多进程)
        // pid_t id = fork();
        // if (id < 0)
        // {
        //     cerr << "fork failed " << errno << endl;
        //     return 5;
        // }
        // else if (id == 0)
        // {
        //     // child
        //     // 子进程会继承父进程的文件描述;由于子进程不需要3号fd(listen_sock)，因此在子进程中关闭
        //     close(listen_sock);

        //     // 此式子进程退出，孙进程开始执行ServerIO()，孙进程变成孤儿进程，由1号进程回收资源
        //     // 该行代码可以取代signal(SIGCHLD, SIG_IGN);
        //     if(fork() > 0) exit(0);
        //     // 提供服务
        //     ServerIO(new_sock);
        //     // 子进程运行完毕,关闭打开的文件描述符(如果不关闭，会造成文件描述符泄露)
        //     close(new_sock);
        //     exit(0);
        // }
        // else
        // {
        //     // parent
        //     // 父进程运行到这，表明子进程已经开始运行
        //     // 父进程需要关闭4号fd，因为new_sock在父进程中没有作用————这样可以让每个客户端连接时都是在4号fd
        //     close(new_sock);
        //     // 子进程进入之后，创建孙进程后，立马推出，父进程需要等待接收子进程的推出信息，否则内存泄漏
        //     waitpid(id, nullptr, 0);
        // }

        // version three ---多线程版本
        // pthread_t tid;
        // int *pram = new int(new_sock);
        // pthread_create(&tid, 0, Handler, pram);

        // version four ---内存池/线程池+任务队列
        MyThreadPool::ThreadPool<MyTask::Task> *tp = MyThreadPool::ThreadPool<MyTask::Task>::GetInstance();
        MyTask::Task t(new_sock);
        tp->PushTask(t);

        // version five ---线程池处理cmd命令,中英互相翻译
    }

    return 0;
}
